/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
// RUN: %clang2mpl --ascii --verify --simple-short-circuit %s -- -Wno-unused-value --target=aarch64-linux-elf
// RUN: cat %m | %FileCheck %s
#include <stddef.h>

#define MYVAR0 0
#define MYVAR1 1
// CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
// CHECK-NEXT: var $gX i32 = -4
int gX = MYVAR1 == 0 ? 4 : -4;
// CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
// CHECK-NEXT: var $gY i32 = 4
int gY = MYVAR0 == 0 ? 4 : -4;

void conditionalOp(int a, int b, int c) {
  // CHECK: LOC 2 [[# @LINE + 5 ]]{{$}}
  // CHECK-NEXT: select i32 (
  // CHECK-NEXT:   ne i32 i32 (dread i32 %a, constval i32 0),
  // CHECK-NEXT:   dread i32 %b,
  // CHECK-NEXT:   dread i32 %c)
  a ? b : c;

  int d;

  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: dassign %_opaque.[[#ONUM:]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %d 0 (select i32 (
  // CHECK-NEXT:   ne i32 i32 (dread i32 %_opaque.[[#ONUM]], constval i32 0),
  // CHECK-NEXT:   dread i32 %_opaque.[[#ONUM]],
  // CHECK-NEXT:   dread i32 %c))
  d = a ?: c;

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %d 0 (dread i32 %c)
  d = MYVAR0 ?: c;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %d 0 (constval i32 1)
  d = MYVAR1 ?: c;
}

struct s {
  char *s;
  int n;
};

void compoundLiteral() {
  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %cle.[[#CLE1:]] 1 (conststr a64 "hi")
  // CHECK-NEXT: dassign %cle.[[#CLE1]] 2 (constval i32 5)
  // CHECK-NEXT: eval (dread agg %cle.[[#CLE1]])
  (struct s){"hi", 5};
  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %cle.[[#CLE2:]] 1 (conststr a64 "hello")
  // CHECK-NEXT: dassign %cle.[[#CLE2]] 2 (constval i32 42)
  // CHECK-NEXT: eval (addrof a64 %cle.[[#CLE2]])
  &(struct s){"hello", 42};
}

void stmtExpr() {
  int x;
  // CHECK: LOC 2 [[# @LINE + 5 ]]{{$}}
  // CHECK-NEXT: var %y i32
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %y 0 (constval i32 4)
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %y, constval i32 5))
  x = ({int y = 4; y + 5;});
}

void predefinedExpr() {
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: conststr a64 "predefinedExpr"
  __FUNCTION__;
}

void comma() {
  int x, y, z;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %x 0 (constval i32 4)
  // CHECK-NEXT: dassign %y 0 (constval i32 5)
  x = 4, y = 5;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // There may be a line for the 42, but it could be optimized out
  // CHECK: dassign %x 0 (dread i32 %y)
  x = (42, y);
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 2))
  // CHECK-NEXT: dassign %z 0 (add i32 (dread i32 %x, dread i32 %y))
  z = (x += 2, x + y);
}

void *alloca(unsigned long size);
void callAlloca() {
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: alloca a64 (constval u64 64)
  alloca(64);
}

void constantP(int x) {
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 1
  __builtin_constant_p(4);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 0
  __builtin_constant_p(x);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 1
  __builtin_constant_p(sizeof(char));
}

struct S {
  float f;
  double d;
};
struct T {
  int i;
  struct S s[10];
};

void offset() {
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval u64 8
  offsetof(struct s, n);
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval u64 48
  offsetof(struct T, s[2].d);
}

void arithmeticTypeCast() {
  int a;
  unsigned long y;

  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: add u64 (
  // CHECK-NEXT:   cvt u64 i32 (dread i32 %a),
  // CHECK-NEXT:   dread u64 %y)
  a + y;
  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: add u64 (
  // CHECK-NEXT:   dread u64 %y,
  // CHECK-NEXT:   cvt u64 i32 (dread i32 %a))
  y + a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: shl u64 (dread u64 %y, dread i32 %a)
  y << a;
}
